// --------------------------------------------------------------------------------------------------------------------
// <copyright file="UIForm.cs" company="Open Trader">
//   Copyright (c) David Denis (david.denis@systemathics.com)
// </copyright>
// <summary>
//   |  Open Trader - The Open Source Systematic Trading Platform
//   |
//   |  This program is free software: you can redistribute it and/or modify
//   |  it under the terms of the GNU General Public License as published by
//   |  the Free Software Foundation, either version 2 of the License, or
//   |  (at your option) any later version.
//   |
//   |  This program is distributed in the hope that it will be useful,
//   |  but WITHOUT ANY WARRANTY; without even the implied warranty of
//   |  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//   |  GNU General Public License for more details.
//   |
//   |  You should have received a copy of the GNU General Public License
//   |  along with this program.  If not, see http://www.gnu.org/licenses
//   |
//   |  Up to date informations about Open Trader can be found at :
//   |    http://opentrader.org
//   |    http://opentrader.codeplex.com
//   |
//   |  For professional services, please visit us at :
//   |    http://www.systemathics.com
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace Org.OpenTrader.Framework.UI.Forms
{
    #region Using Directives

    using System;
    using System.Collections.Generic;
    using System.Drawing;
    using System.Linq;
    using System.Threading;
    using System.Windows.Forms;

    using Interfaces.UI;

    using Org.OpenTrader.Framework.Enums;
    using Org.OpenTrader.Framework.Events;

    #endregion

    /// <summary>
    /// The ui form.
    /// </summary>
    public partial class UIForm : Form, IUIForm
    {
        #region Constants and Fields

        /// <summary>
        /// The TitleBarHeight.
        /// </summary>
        public const int TitleBarHeight = 28;

        /// <summary>
        /// The TitleBarWidth.
        /// </summary>
        public const int TitleBarWidth = 28;

        /// <summary>
        /// The XMargin.
        /// </summary>
        public const int XMargin = 2;

        /// <summary>
        /// The YMargin.
        /// </summary>
        public const int YMargin = 2;

        /// <summary>
        /// The forms.
        /// </summary>
        private static readonly List<UIForm> forms = new List<UIForm>();

        /// <summary>
        /// The control.
        /// </summary>
        private readonly UIControl control;

        /// <summary>
        /// The close.
        /// </summary>
        private Button close;

        /// <summary>
        /// The closeType.
        /// </summary>
        private EUIFormClosingType closeType;

        /// <summary>
        /// The dragging.
        /// </summary>
        private volatile bool dragging;

        /// <summary>
        /// The label.
        /// </summary>
        private UITitleBar label;

        /// <summary>
        /// The layout.
        /// </summary>
        private EUIFormLayoutType layout;

        /// <summary>
        /// The offset.
        /// </summary>
        private Point offset;

        /// <summary>
        /// The visibility.
        /// </summary>
        private EUIFormVisibility visibility;

        #endregion

        /////// <summary>
        /////// Initializes a new instance of the <see cref="UIForm"/> class.
        /////// </summary>
        ////public UIForm()
        ////{
        ////    this.InitializeComponent();
        ////    this.Owner = RootForm;
        ////    // Devel.ExecutedFrom("UIForm.Constructor " + GetHashCode());
        ////}
        #region Constructors and Destructors

        /// <summary>
        /// Initializes a new instance of the <see cref="UIForm"/> class.
        /// </summary>
        /// <param name="title">
        /// The title.
        /// </param>
        /// <param name="layoutType">
        /// The layoutType.
        /// </param>
        /// <param name="closeType">
        /// The closeType.
        /// </param>
        /// <param name="ctrl">
        /// The ctrl.
        /// </param>
        public UIForm(string title, EUIFormLayoutType layoutType, EUIFormClosingType closeType, UIControl ctrl)
        {
            this.InitializeComponent();

            Application.CurrentCulture = Constants.CultureInfo;
            Thread.CurrentThread.CurrentCulture = Constants.CultureInfo;
            Thread.CurrentThread.CurrentUICulture = Constants.CultureInfo;

            // Devel.ExecutedFrom("UIForm.Constructor (" + title + ") " + GetHashCode());
            this.closeType = closeType;
            this.layout = layoutType;
            this.control = (UIControl)ctrl;

            this.DoLayout();

            this.Title = title;

            lock (forms)
            {
                forms.Add(this);
            }

            if (this.closeType == EUIFormClosingType.Hard)
            {
                this.close.Text = "X";
            }
            else
            {
                this.close.Text = "_";
            }

            if (FormEventCB != null)
            {
                FormEventCB(this, new FormEventArgs.Created());
            }

            ////var rootForm = this.RootForm;
            ////if (rootForm != null)
            ////{
            ////    this.Owner = this.RootForm;
            ////}
        }

        #endregion

        #region Delegates

        /// <summary>
        /// The change visibily delegate.
        /// </summary>
        private delegate void ChangeVisibilyDelegate();

        #endregion

        #region Events

        /// <summary>
        /// Very simple form that contains only one control
        /// - The form has no regular border/title bar/resize box 
        /// - Instead the title bar is a label painted inside the painting area
        /// - The title bar can be at top (horizontal), left or right (vertical)
        /// - The window is draggable using the title bar
        /// - The window cannot be resized
        /// - The window will have the size to contain only the given control, the menu bar and a close button (size is set automatically)
        /// - FormEUIFormClosingType mode can be soft (just hide and minimize) or hard (destroy)
        /// Using this form is quite simple
        /// - Create a control that sublcass UIControl
        /// - Put anything you want inside it (buttons, grids, groupboxes, events callbacks, etc ...)
        /// - Create a simple form and give it the created control reference. Done !
        /// </summary>
        public static event EventHandler<FormEventArgs> FormEventCB;

        /// <summary>
        /// The closed cb.
        /// </summary>
        public event EventHandler<FormEventArgs> EventCB;

        #endregion

        #region Properties

        /// <summary>
        /// Gets ExistingForms.
        /// </summary>
        public static List<UIForm> ExistingForms
        {
            get
            {
                lock (forms)
                {
                    return forms;
                }
            }
        }

        /// <summary>
        /// Gets or sets FormEUIFormClosingType.
        /// </summary>
        public EUIFormClosingType FormEUIFormClosingType
        {
            get
            {
                return this.closeType;
            }

            set
            {
                this.closeType = value;
            }
        }

        /// <summary>
        /// Gets or sets FormlayoutType.
        /// </summary>
        public EUIFormLayoutType FormlayoutType
        {
            get
            {
                return this.layout;
            }

            set
            {
                this.layout = value;
                this.DoLayout();
            }
        }

        /// <summary>
        /// Gets RootForm.
        /// </summary>
        public UIForm RootForm
        {
            get
            {
                UIForm form = null;

                var c = from f in ExistingForms where f.Title.IndexOf("*") == 0 select f;
                if (c.Count() > 0)
                {
                    form = c.First();
                }

                if (form == this)
                {
                    form = null;
                }

                Stdout.WriteLine(string.Format("RootForm for {0} is {1}", this.Title, form != null ? form.Title : "null"));
                return form;
            }
        }

        /// <summary>
        /// Gets or sets Title.
        /// </summary>
        public string Title
        {
            get
            {
                return this.label.Text;
            }

            set
            {
                this.label.Text = value;
                this.Text = value;
            }
        }

        /// <summary>
        /// Gets or sets Visibility.
        /// </summary>
        public EUIFormVisibility Visibility
        {
            get
            {
                return this.visibility;
            }

            set
            {
                if (value == this.visibility)
                {
                    return;
                }

                ChangeVisibilyDelegate d = null;
                switch (value)
                {
                    case EUIFormVisibility.Invert:
                        {
                            if (this.Visibility == EUIFormVisibility.Show)
                            {
                                this.Visibility = EUIFormVisibility.Hide;
                            }
                            else if (this.Visibility == EUIFormVisibility.Hide)
                            {
                                this.Visibility = EUIFormVisibility.Show;
                            }
                        }

                        break;

                    case EUIFormVisibility.Show:
                        {
                            this.visibility = value;
                            d = new ChangeVisibilyDelegate(
                                () =>
                                    {
                                        this.Show();
                                        this.WindowState = FormWindowState.Normal;
                                        this.BringToFront();
                                    });
                        }

                        break;

                    case EUIFormVisibility.Hide:
                        {
                            this.visibility = value;
                            d = new ChangeVisibilyDelegate(
                                () =>
                                    {
                                        this.SendToBack();
                                        this.Hide();
                                        this.WindowState = FormWindowState.Minimized;
                                    });
                        }

                        break;

                    case EUIFormVisibility.ShowDialog:
                        {
                            this.visibility = value;
                            d = new ChangeVisibilyDelegate(() => this.ShowDialog());
                        }

                        break;
                }

                if (d == null)
                {
                    return;
                }

                d();
            }
        }

        #endregion

        #region Public Methods

        /// <summary>
        /// The destroy.
        /// </summary>
        public void Destroy()
        {
            this.Close();
        }

        /// <summary>
        /// The do layout_ vertical.
        /// </summary>
        /// <param name="titlebarAtLeft">
        /// The titlebarAtLeft.
        /// </param>
        public void DoLayoutVertical(bool titlebarAtLeft)
        {
            // Size Window
            this.ClientSize = new Size(TitleBarWidth + this.control.Size.Width + XMargin, YMargin + this.control.Size.Height + YMargin);

            if (titlebarAtLeft)
            {
                // Contained control is positionned
                this.control.Location = new Point(TitleBarWidth, YMargin);
                this.control.Margin = new Padding(0);

                // HardOrSoftClosed Button
                this.close.Location = new Point(0, 4);

                // FormTitle 
                this.label.Vertical = true;
                this.label.Location = new Point(4, 40);
            }
            else
            {
                // Contained control is positionned
                this.control.Location = new Point(XMargin, YMargin);
                this.control.Margin = new Padding(0);

                // HardOrSoftClosed Button
                this.close.Location = new Point(this.Size.Width - this.close.Size.Width - 4, 4);

                // FormTitle 
                this.label.Vertical = true;
                this.label.Location = new Point(this.Size.Width - TitleBarWidth + 4, 40);
            }
        }

        #endregion

        #region Methods

        /// <summary>
        /// The on handle created.
        /// </summary>
        /// <param name="e">
        /// The e.
        /// </param>
        protected override void OnHandleCreated(EventArgs e)
        {
            // Devel.ExecutedFrom("UIForm.OnHandleCreated " + GetHashCode() );
            this.close.Click += this.HandlerClose;
            this.label.MouseDown += this.HandlerMouseDown;
            this.label.MouseUp += this.HandlerMouseUp;
            this.label.MouseMove += this.HandlerMouseMove;
            this.control.SizeChanged += this.HandlerControlSizeChanged;
            this.FormClosing += this.UIFormFormClosing;

            base.OnHandleCreated(e);
        }

        /// <summary>
        /// The on handle destroyed.
        /// </summary>
        /// <param name="e">
        /// The e.
        /// </param>
        protected override void OnHandleDestroyed(EventArgs e)
        {
            // Devel.ExecutedFrom("UIForm.OnHandleDestroyed " + GetHashCode() );
            this.close.Click -= this.HandlerClose;
            this.label.MouseDown -= this.HandlerMouseDown;
            this.label.MouseUp -= this.HandlerMouseUp;
            this.label.MouseMove -= this.HandlerMouseMove;
            this.control.SizeChanged -= this.HandlerControlSizeChanged;
            this.FormClosing -= this.UIFormFormClosing;

            base.OnHandleDestroyed(e);
        }

        /// <summary>
        /// The do layout.
        /// </summary>
        /// <exception cref="Exception">
        /// </exception>
        private void DoLayout()
        {
            // SuspendLayout();
            this.StartPosition = FormStartPosition.CenterParent;

            if (this.Controls.Contains(this.close))
            {
                this.Controls.Remove(this.close);
            }

            if (this.Controls.Contains(this.label))
            {
                this.Controls.Remove(this.label);
            }

            if (this.Controls.Contains(this.control))
            {
                this.Controls.Remove(this.control);
            }

            switch (this.layout)
            {
                case EUIFormLayoutType.TitleBarAtTop:
                    this.DoLayoutHorizontal();
                    break;
                case EUIFormLayoutType.TitleBarAtLeft:
                    this.DoLayoutVertical(true);
                    break;
                case EUIFormLayoutType.TitleBarAtRight:
                    this.DoLayoutVertical(false);
                    break;
                default:
                    throw new Exception("Not supported");
            }

            if (this.closeType != EUIFormClosingType.None)
            {
                this.Controls.Add(this.close);
            }

            this.Controls.Add(this.label);
            this.Controls.Add(this.control);

            // ResumeLayout(false);
            // PerformLayout();
        }

        /// <summary>
        /// The do layout_ horizontal.
        /// </summary>
        private void DoLayoutHorizontal()
        {
            // Size Window
            this.ClientSize = new Size(XMargin + this.control.Size.Width + XMargin, TitleBarHeight + this.control.Size.Height + YMargin);

            // Contained control is positionned
            this.control.Location = new Point(XMargin, TitleBarHeight);
            this.control.Margin = new Padding(0);

            // HardOrSoftClosed Button
            this.close.Location = new Point(this.Size.Width - this.close.Width - 4, 4);

            // FormTitle
            this.label.Vertical = false;
            this.label.Location = new Point(XMargin, 4);
        }

        /// <summary>
        /// The handler_ close.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="e">
        /// The e.
        /// </param>
        private void HandlerClose(object sender, EventArgs e)
        {
            // Send event
            if (this.EventCB != null)
            {
                this.EventCB(this, new FormEventArgs.HardOrSoftClosed());
            }

            switch (this.closeType)
            {
                case EUIFormClosingType.Hard:
                    this.Dispose();
                    break;

                case EUIFormClosingType.Soft:
                    this.Visibility = EUIFormVisibility.Hide;
                    break;
            }
        }

        /// <summary>
        /// The handler_ control size changed.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="e">
        /// The e.
        /// </param>
        private void HandlerControlSizeChanged(object sender, EventArgs e)
        {
            this.DoLayout();
        }

        /// <summary>
        /// The handler_ mouse down.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="e">
        /// The e.
        /// </param>
        private void HandlerMouseDown(object sender, MouseEventArgs e)
        {
            this.dragging = true;
            this.offset.X = e.X;
            this.offset.Y = e.Y;
        }

        /// <summary>
        /// The handler_ mouse move.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="e">
        /// The e.
        /// </param>
        private void HandlerMouseMove(object sender, MouseEventArgs e)
        {
            if (this.dragging)
            {
                var currentScreenPos = this.PointToScreen(e.Location);
                this.Location = new Point(currentScreenPos.X - this.offset.X, currentScreenPos.Y - this.offset.Y);
            }
        }

        /// <summary>
        /// The handler_ mouse up.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="e">
        /// The e.
        /// </param>
        private void HandlerMouseUp(object sender, MouseEventArgs e)
        {
            this.dragging = false;
        }

        /// <summary>
        /// The ui form form closing.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="e">
        /// The e.
        /// </param>
        private void UIFormFormClosing(object sender, FormClosingEventArgs e)
        {
            e.Cancel = true;
            this.HandlerClose(sender, e);
        }

        /// <summary>
        /// The ui form shown.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="e">
        /// The e.
        /// </param>
        private void UIFormShown(object sender, EventArgs e)
        {
            this.visibility = EUIFormVisibility.Show;
            Stderr.WriteLine("UIFormShown");
        }

        #endregion
    }
}